
#include "rtc.h"
#include "ints.h"
/** converts BCD (Binary Coded Decimal) to decimal
 */
Byte bcd2dec(Byte i)
{
	return ((i >> 4)*10+(i & 0x0F));
}

/** converts decimal to BCD (Binary Coded Decimal)
 */
Byte dec2bcd(Byte i)
{
	return ((i/10)<<4)+(i%10);
}

/** Wait until data in rtc is valid.
 * Data is valid until +/- 240 usec after this function returns,
 * thus a read/write can be done to the RTC within this time period
 */
void rtc_valid()
{
	//
	disable_irq(RTC_IRQ ); 
	outportb(RTC_ADDR_REG, RTC_STAT_A); // read STAT_A
	
	// wait if Update In Progress (UIP)
	while (inportb(RTC_DATA_REG) & RTC_UIP)
	; // data is invalid
	
	enable_irq(RTC_IRQ );

}

/** Returns rtc data from I/O address add. Doesn't check valid bit
 */
Byte read_rtc(Byte add)
{
	//
	disable_irq(RTC_IRQ ); 
	
	outportb(RTC_ADDR_REG, add);
	const Byte ret = inportb(RTC_DATA_REG);
	
	enable_irq(RTC_IRQ );
	
	return ret;
}

/** Returns rtc data from I/O address add. Check valid bit
 */
Byte read_rtcv(Byte add)
{
	rtc_valid();
	return read_rtc(add);

}


/** Write value to I/O address add. Doesn't check valid bit
 */
void write_rtc(Byte add, Byte value)
{
	disable_irq(RTC_IRQ ); 
	
	outportb(RTC_ADDR_REG, add);
	outportb(RTC_DATA_REG, value);
	
	enable_irq(RTC_IRQ );
}

/** Write value to I/O address add. Check valid bit
 */
void write_rtcv(Byte add, Byte value)
{
	rtc_valid();
	write_rtc(add, value);
}

/** Read RTC stored time
 *
 * Uses read_rtcv() and bcd2dec()
 */
void rtc_read_time(RTC_TIME * currentTime)
{

	currentTime->hour = bcd2dec(read_rtcv(HOUR));
	currentTime->min =  bcd2dec(read_rtcv(MIN));
	currentTime->sec =  bcd2dec(read_rtcv(SEC));
	
}

/** Read RTC stored date
 *
 * Uses read_rtcv() and bcd2dec()
 */
void rtc_read_date(RTC_DATE * currentDate)
{
	currentDate->day =  bcd2dec(read_rtcv(MONTH_DAY));
	currentDate->month= bcd2dec(read_rtcv(MONTH));
	currentDate->year=	bcd2dec(read_rtcv(YEAR));
}

/** Read RTC stored alarm
 *
 * Uses read_rtcv() and bcd2dec()
 */
void rtc_read_alarm(RTC_TIME *currentAlarm)
{
	currentAlarm->hour = bcd2dec(read_rtcv(HOUR_ALARM));
	currentAlarm->min =  bcd2dec(read_rtcv(MIN_ALARM));
	currentAlarm->sec =  bcd2dec(read_rtcv(SEC_ALARM));

}

/** Write alarm to RTC
 *
 * Uses write_rtcv() and dec2bcd()
 */
void rtc_write_alarm(RTC_TIME *newAlarm)
{
	write_rtcv(SEC_ALARM, dec2bcd(newAlarm->sec));
	write_rtcv(MIN_ALARM, dec2bcd(newAlarm->min));
	write_rtcv(HOUR_ALARM, dec2bcd(newAlarm->hour));
}
